package monitor

import (
	"context"
	"encoding/json"
	"fmt"
	gorillaWs "github.com/gorilla/websocket"
	"github.com/kataras/iris/v12/websocket"
	"github.com/kataras/neffos"
	"github.com/kataras/neffos/gorilla"
	apis2 "gluenet/pkg/apis"
	"math/rand"
	"net/http"
	"time"
)

const (
	netWork = `
from(bucket: "data")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_measurement"] == "prometheus_remote_write")
  |> filter(fn: (r) => r["_field"] == "container_network_receive_packets_total")
  |> filter(fn: (r) => r["namespace"] == "c2b3d77aba89658d6d31754d244647b8")
  |> filter(fn: (r) => r["service"] == "kubelet")
  |> filter(fn: (r) => r["pod"] == "jaeger-glue")
  |> filter(fn: (r) => r["id"] =~ /^\/kubepods.*/)
`
)

func NetWorkRecv(c *apis2.GlueContext) {
	//var data []map[string]interface{}
	startTime, _ := c.WebContext.URLParamInt64("start")
	endTime, _ := c.WebContext.URLParamInt64("end")
	lookBack, _ := c.WebContext.URLParamInt64("lookback")
	_ = c.WebContext.URLParam("guid")

	if lookBack != 0 {
		endTime = time.Now().Unix()
		startTime = endTime - lookBack + 1
	}
	size := endTime - startTime + 1

	c.Logger.Debugf("size: %v", size)
	if size <= 0 {
		c.Logger.Errorf("error : size less < than")
		c.WebContext.JSON(apis2.ResponseReqErr(fmt.Errorf("error : size less < than"), nil))
		return
	}

	data := map[string]interface{}{
		"instance1": simulateNetWorkRecv(startTime, endTime),
		"instance2": simulateNetWorkRecv(startTime, endTime),
	}

	c.WebContext.JSON(data)
}

func NetWorkSend(c *apis2.GlueContext) {
	//var data []map[string]interface{}
	startTime, _ := c.WebContext.URLParamInt64("start")
	endTime, _ := c.WebContext.URLParamInt64("end")
	lookBack, _ := c.WebContext.URLParamInt64("lookback")
	_ = c.WebContext.URLParam("guid")

	if lookBack != 0 {
		endTime = time.Now().Unix()
		startTime = endTime - lookBack + 1
	}
	size := endTime - startTime + 1

	c.Logger.Debugf("size: %v", size)
	if size <= 0 {
		c.Logger.Errorf("error : size less < than")
		c.WebContext.JSON(apis2.ResponseReqErr(fmt.Errorf("error : size less < than"), nil))
		return
	}

	//data = simulateNetWorkSend(startTime, endTime)

	data := map[string]interface{}{
		"instance1": simulateNetWorkSend(startTime, endTime),
		"instance2": simulateNetWorkSend(startTime, endTime),
	}
	c.WebContext.JSON(data)
}

func GetNetWorkRecvSocket(c *apis2.GlueContext) {
	_ = c.WebContext.URLParam("guid")

	ctx, cancel := context.WithCancel(c.Context)
	var ActuallyNodeCpu = websocket.New(gorilla.Upgrader(gorillaWs.Upgrader{
		CheckOrigin: func(*http.Request) bool { return true },
	}), websocket.Events{
		websocket.OnNativeMessage: func(conn *neffos.NSConn, message neffos.Message) error { return nil },
	})

	ActuallyNodeCpu.OnConnect = func(n *websocket.Conn) error {
		c.Logger.Debugf("OnConnect from server %v", n.ID())
		tk := time.NewTicker(time.Second * 3)
		for {
			select {
			case <-tk.C:
				//var data []map[string]interface{}
				//if err := c.DataBase.QueryList(nodeCpulast, impl.SqlDataBaseInfluxdb, &data); err != nil {
				//	c.Logger.Errorf("query error %v", err)
				//}
				end := time.Now().Unix()
				start := end - 2
				data := map[string]interface{}{
					"instance1": simulateNetWorkRecv(start, end),
					"instance2": simulateNetWorkRecv(start, end),
				}

				bts, _ := json.Marshal(data)
				n.Write(neffos.Message{
					Body:     bts,
					IsNative: true,
				})
			case <-ctx.Done():
				c.Logger.Debugf("push down %v", n.ID())
				return nil
			}
		}
		return nil
	}

	ActuallyNodeCpu.OnDisconnect = func(n *websocket.Conn) {
		cancel()
		c.Logger.Debugf("Disconnected from server", n.ID())
	}

	ActuallyNodeCpu.OnUpgradeError = func(err error) {
		cancel()
		c.Logger.Debugf("OnUpgradeError from server %v", err)
	}

	websocket.Handler(ActuallyNodeCpu)(c.WebContext)
}

func GetNetWorkSendSocket(c *apis2.GlueContext) {
	_ = c.WebContext.URLParam("guid")

	ctx, cancel := context.WithCancel(c.Context)
	var ActuallyNodeCpu = websocket.New(gorilla.Upgrader(gorillaWs.Upgrader{
		CheckOrigin: func(*http.Request) bool { return true },
	}), websocket.Events{
		websocket.OnNativeMessage: func(conn *neffos.NSConn, message neffos.Message) error { return nil },
	})

	ActuallyNodeCpu.OnConnect = func(n *websocket.Conn) error {
		c.Logger.Debugf("OnConnect from server %v", n.ID())
		tk := time.NewTicker(time.Second * 3)
		for {
			select {
			case <-tk.C:
				//var data []map[string]interface{}
				//if err := c.DataBase.QueryList(nodeCpulast, impl.SqlDataBaseInfluxdb, &data); err != nil {
				//	c.Logger.Errorf("query error %v", err)
				//}
				end := time.Now().Unix()
				start := end - 2
				data := map[string]interface{}{
					"instance1": simulateNetWorkSend(start, end),
					"instance2": simulateNetWorkSend(start, end),
				}

				bts, _ := json.Marshal(data)
				n.Write(neffos.Message{
					Body:     bts,
					IsNative: true,
				})
			case <-ctx.Done():
				c.Logger.Debugf("push down %v", n.ID())
				return nil
			}
		}
		return nil
	}

	ActuallyNodeCpu.OnDisconnect = func(n *websocket.Conn) {
		cancel()
		c.Logger.Debugf("Disconnected from server", n.ID())
	}

	ActuallyNodeCpu.OnUpgradeError = func(err error) {
		cancel()
		c.Logger.Debugf("OnUpgradeError from server %v", err)
	}

	websocket.Handler(ActuallyNodeCpu)(c.WebContext)
}

func simulateNetWorkRecv(start, end int64) []map[string]interface{} {
	size := end - start + 1
	data := make([]map[string]interface{}, size)
	for i := int64(0); i < size; i++ {
		t := time.Unix(i+start, 0)
		v := float64(t.Second())/2*1024*20 + 1024*1024*10 + rand.Float64()*1024*20
		data[i] = map[string]interface{}{
			"label": "net_work_recv_bytes",
			"time":  t.Format(time.RFC3339Nano),
			"value": int64(v),
			"limit": 0,
		}
	}
	return data
}

func simulateNetWorkSend(start, end int64) []map[string]interface{} {
	size := end - start + 1
	data := make([]map[string]interface{}, size)
	for i := int64(0); i < size; i++ {
		t := time.Unix(i+start, 0)
		v := float64(t.Second())/2*1024*14 + 1024*1024*7 + rand.Float64()*1024*9
		data[i] = map[string]interface{}{
			"label": "net_work_send_bytes",
			"time":  t.Format(time.RFC3339Nano),
			"value": int64(v),
			"limit": 0,
		}
	}
	return data
}
